package com.ctw.mall.service.impl;

import com.ctw.mall.dao.ProductMapper;
import com.ctw.mall.enums.ProductStatusEnum;
import com.ctw.mall.enums.ResponseEnum;
import com.ctw.mall.form.CartAddForm;
import com.ctw.mall.form.CartUpdateForm;
import com.ctw.mall.pojo.Cart;
import com.ctw.mall.pojo.Product;
import com.ctw.mall.service.ICartService;
import com.ctw.mall.vo.CartProductVo;
import com.ctw.mall.vo.CartVo;
import com.ctw.mall.vo.ResponseVo;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class CartServiceImpl implements ICartService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Gson gson = new Gson();

    private final static String CART_REDIS_KEY_TEMPLATE = "cart_%d";


    @Override
    public ResponseVo<CartVo> add(Integer uid,CartAddForm form) {

        Integer quantity = 1;

        //判断商品是否存在
        Product product = productMapper.selectByPrimaryKey(form.getProductId());
        if(product == null){
            return ResponseVo.error(ResponseEnum.PRODUCT_NOT_EXIST);
        }

        //商品是否正常在售
        if(!product.getStatus().equals(ProductStatusEnum.ON_SALE.getCode())){
            return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETE);
        }

        //商品库存是否充足
        if(product.getStock()<= 0){
            return ResponseVo.error(ResponseEnum.PRODUCT_STOCK_LACK);
        }

        //写入redis,springboot往redis写入数据
        /*
         * 1.引入依赖
         * 2.用封装好的类StringRedisTemplate，的方法
         */

        //key:cart_1
        //三个参数:redis的key,hash的key，value
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        Cart cart;
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        //通过id（key）查找出来原购物车的信息
        //用get方法只能获取一条数据
        String value = opsForHash.get(redisKey, String.valueOf(product.getId()));
        if(StringUtils.isEmpty(value)){
            //redis内没有商品
            cart = new Cart(product.getId(),quantity,form.getSelected());
        }else{
            //已有，数量+1
            //前一个是需要转的值，后面是要转的对象类型
            cart = gson.fromJson(value,Cart.class);
            cart.setQuantity(cart.getQuantity()+quantity);
        }

        opsForHash.put(redisKey,
               String.valueOf(product.getId()),
               gson.toJson(cart));
                //第二个参数为string类型,但是传入的是对象，需要转换
        return list(uid);
    }


    @Override
    public ResponseVo<CartVo> update(Integer uid, Integer productId, CartUpdateForm form) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);

        //通过id（key）查找出来原购物车的信息
        String value = opsForHash.get(redisKey, String.valueOf(productId));
        if(StringUtils.isEmpty(value)){
            //redis内没有商品，报错
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }
        //已有，修改内容
        //前一个是需要转的值，后面是要转的对象类型
         Cart cart = gson.fromJson(value,Cart.class);

        if(form.getQuantity()!=null&&form.getQuantity()>=0){
            cart.setQuantity(form.getQuantity());
        }
        if(form.getSelected() !=null){
            cart.setProductSelected(form.getSelected());
        }

        //将购物车设置进
        opsForHash.put(redisKey,String.valueOf(productId),gson.toJson(cart));

        return list(uid);
    }


    //若将购物车内所有的数据删掉，购物车也将删掉
    //传入uid，productId，将一行数据删除
    @Override
    public ResponseVo<CartVo> delete(Integer uid, Integer productId) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        //通过id（key）查找出来原购物车的信息
        String value = opsForHash.get(redisKey, String.valueOf(productId));
        if(StringUtils.isEmpty(value)){
            //redis内没有商品，报错
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }
       //有该商品，直接删除
        opsForHash.delete(redisKey,String.valueOf(productId));
        return list(uid);
    }


    @Override
    public ResponseVo<CartVo> selectAll(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);

        for(Cart cart : listForCart(uid)){
            cart.setProductSelected(true);
            //写入缓存
            opsForHash.put(redisKey,String.valueOf(cart.getProductId()),gson.toJson(cart));
        }

        return list(uid);
    }


    @Override
    public ResponseVo<CartVo> unSelectAll(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);

        for(Cart cart : listForCart(uid)){
            cart.setProductSelected(false);
            //写入缓存
            opsForHash.put(redisKey,String.valueOf(cart.getProductId()),gson.toJson(cart));
        }
        return list(uid);
    }


    @Override
    //TODO ???流
    public ResponseVo<Integer> sum(Integer uid) {
        Integer sum = listForCart(uid).stream()
                .map(Cart::getQuantity).reduce(0,Integer::sum);//从0开始加
        return ResponseVo.success(sum);
    }


    @Override
    public ResponseVo<CartVo> list(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        Map<String, String> entries = opsForHash.entries(redisKey);

        boolean selectAll = true;
        Integer cartTotalQuantity =0;
        BigDecimal cartTotalPrice = BigDecimal.ZERO;

        CartVo cartVo = new CartVo();
        List<CartProductVo> cartProductVoList = new ArrayList<>();
        //遍历购物车
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Integer productId = Integer.valueOf(entry.getKey());
            Cart cart = gson.fromJson(entry.getValue(),Cart.class);
            //TODO 需要优化，使用mysql里面的in
            Product product = productMapper.selectByPrimaryKey(productId);
            if(product!=null){
                CartProductVo cartProductVo = new CartProductVo(productId,cart.getQuantity(),product.getName(),product.getSubtitle(),
                                                                product.getMainImage(),product.getPrice(),product.getStatus(),
                                                                product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())),product.getStock(),cart.getProductSelected());
                cartProductVoList.add(cartProductVo);
                if(!cart.getProductSelected()){
                    selectAll = false;
                }
                if(cartProductVo.getProductSelected()) {
                    cartTotalPrice=cartTotalPrice.add(cartProductVo.getProductTotalPrice());
                }
            }
            cartTotalQuantity+=cart.getQuantity();
        }

        cartVo.setSelectAll(selectAll);
        cartVo.setCartTotalQuantity(cartTotalQuantity);
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setCartProductVoList(cartProductVoList);

        return ResponseVo.success(cartVo);
    }

    //用于遍历购物车的方法,返回购物车信息列表
    public   List<Cart> listForCart(Integer uid){
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE,uid);
        Map<String, String> entries = opsForHash.entries(redisKey);
        List<Cart> cartList = new ArrayList<>();
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            cartList.add(gson.fromJson(entry.getValue(),Cart.class));
        }
        return  cartList;
    }


    //订单列表





}
